//! Simple GPIO Test Program for Orange Pi 5 Plus
//! 
//! This is a minimal example showing how to integrate the GPIO driver
//! into your application.

#![no_std]
#![no_main]

extern crate alloc;
use core::panic::PanicInfo;

// GPIO driver
use axplat_aarch64_peripherals::rk3588_gpio::{
    init_all, GpioPin, GpioPinHandle, GpioDirection, GpioTrigger,
};
use axplat::mem::VirtAddr;

// GPIO base addresses (physical addresses need to be mapped to virtual)
const GPIO0_BASE: usize = 0xFD8A0000;
const GPIO1_BASE: usize = 0xFEC20000;
const GPIO2_BASE: usize = 0xFEC30000;
const GPIO3_BASE: usize = 0xFEC40000;
const GPIO4_BASE: usize = 0xFEC50000;

/// Initialize GPIO subsystem
pub fn gpio_init() {
    // Map physical addresses to virtual addresses
    // In a real OS, you would use your memory mapping functions
    let gpio_bases = [
        VirtAddr::from(GPIO0_BASE),
        VirtAddr::from(GPIO1_BASE),
        VirtAddr::from(GPIO2_BASE),
        VirtAddr::from(GPIO3_BASE),
        VirtAddr::from(GPIO4_BASE),
    ];
    
    // Initialize all GPIO controllers
    init_all(&gpio_bases);
}

/// Test 1: Simple LED blink
pub fn test_led_blink() {
    // Using GPIO4_B0 as LED output
    let mut led = GpioPinHandle::new(GpioPin::GPIO4_B0, GpioDirection::Output);
    
    for _ in 0..10 {
        led.set_high();
        delay_ms(500);
        led.set_low();
        delay_ms(500);
    }
}

/// Test 2: Button input
pub fn test_button_input() {
    // Using GPIO3_A0 as button input
    let button = GpioPinHandle::new(GpioPin::GPIO3_A0, GpioDirection::Input);
    
    loop {
        if button.is_high() {
            // Button pressed
            break;
        }
        delay_ms(10);
    }
}

/// Test 3: Button controlled LED
pub fn test_button_led() {
    let mut led = GpioPinHandle::new(GpioPin::GPIO4_B0, GpioDirection::Output);
    let button = GpioPinHandle::new(GpioPin::GPIO3_A0, GpioDirection::Input);
    
    for _ in 0..100 {
        if button.is_high() {
            led.set_high();
        } else {
            led.set_low();
        }
        delay_ms(10);
    }
}

/// Test 4: Running light (Knight Rider effect)
pub fn test_running_light() {
    // Use 8 consecutive pins
    let mut leds = [
        GpioPinHandle::new(GpioPin::new(4, 0), GpioDirection::Output),
        GpioPinHandle::new(GpioPin::new(4, 1), GpioDirection::Output),
        GpioPinHandle::new(GpioPin::new(4, 2), GpioDirection::Output),
        GpioPinHandle::new(GpioPin::new(4, 3), GpioDirection::Output),
        GpioPinHandle::new(GpioPin::new(4, 4), GpioDirection::Output),
        GpioPinHandle::new(GpioPin::new(4, 5), GpioDirection::Output),
        GpioPinHandle::new(GpioPin::new(4, 6), GpioDirection::Output),
        GpioPinHandle::new(GpioPin::new(4, 7), GpioDirection::Output),
    ];
    
    // Forward sweep
    for i in 0..8 {
        leds[i].set_high();
        delay_ms(100);
        leds[i].set_low();
    }
    
    // Backward sweep
    for i in (0..8).rev() {
        leds[i].set_high();
        delay_ms(100);
        leds[i].set_low();
    }
}

/// Test 5: GPIO interrupt test
pub fn test_interrupt() {
    let mut button = GpioPinHandle::new(GpioPin::GPIO3_A0, GpioDirection::Input);
    let mut led = GpioPinHandle::new(GpioPin::GPIO4_B0, GpioDirection::Output);
    
    // Configure interrupt on rising edge
    button.set_interrupt(GpioTrigger::RisingEdge);
    
    // In your actual interrupt handler (registered with GIC):
    // fn gpio3_interrupt_handler() {
    //     use axplat_aarch64_peripherals::rk3588_gpio::{get_interrupt_status, irq_handler};
    //     let status = get_interrupt_status(3);
    //     if status & 0x01 != 0 {  // Check if pin 0 triggered
    //         // Toggle LED in response to button press
    //         led.toggle();
    //     }
    //     irq_handler(3);  // Clear interrupt and call handlers
    // }
    
    // Wait for interrupt (in real system, this would be handled by interrupt handler)
    led.set_high();
}

/// Placeholder delay function
/// In a real system, you would use your timer/delay implementation
fn delay_ms(_ms: u32) {
    // Implementation depends on your timer driver
    // Example: axhal::time::busy_wait_us(ms * 1000);
    for _ in 0..(_ms * 10000) {
        core::hint::spin_loop();
    }
}

// Main entry point (example structure)
#[no_mangle]
pub extern "C" fn main() -> ! {
    // Initialize GPIO
    gpio_init();
    
    // Run tests
    test_led_blink();
    test_button_input();
    test_button_led();
    test_running_light();
    
    // Infinite loop
    loop {
        delay_ms(1000);
    }
}

// Panic handler (minimal example)
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    loop {
        core::hint::spin_loop();
    }
}

